export function aop(f, { before, after, thisArg = null, immediate = false } = {}, ...rest) {
  const _ = function (..._args) {
    let result
    const args = rest.concat(_args)
    if (typeof before === 'function') {
      const beforeResult = before.apply(thisArg, args)
      if (!beforeResult) {
        return beforeResult
      }
      result = f.apply(thisArg, [...args, beforeResult])
    } else {
      result = f.apply(thisArg, args)
    }
    typeof after === 'function' && after.apply(thisArg, [...args, result])
    return result
  }

  return immediate ? _() : _
}

export function aopFactory(before, after, { thisArg = null, immediate = false, args = [] } = {}) {
  const _thisArg = thisArg,
    _immediate = immediate
  return function (f, { thisArg = _thisArg, immediate = _immediate } = {}, ...rest) {
    return aop(f, { before, after, thisArg, immediate }, ...args.concat(rest))
  }
}
